﻿using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OculusWrap;
using ovrBool = System.Byte;
using ovrSession = System.IntPtr;

namespace OculusWrapTest
{
	[TestClass]
	public class OVRTest
	{
		#region Helper methods
		/// <summary>
		/// Creates the session used in the unit tests in this class.
		/// </summary>
		/// <returns>Created unmanaged session object.</returns>
		private ovrSession CreateSession()
		{
			IntPtr					session			= IntPtr.Zero;
			OVRTypes.GraphicsLuid	graphicsLuid	= new OVRTypes.GraphicsLuid();
			OVRTypes.Result			result;

			result = OVR.Create(ref session, ref graphicsLuid);
			Assert.IsTrue(result >= OVRTypes.Result.Success, "Failed to create a session. This usually indicates that the HMD is turned off.");
			Assert.AreNotEqual(IntPtr.Zero, session, "No session returned, even though create call succeeded.");

			return session;
		}
		#endregion

		#region Helper properties
		/// <summary>
		/// Pointer to the DllOvr module, after it has been loaded, using a call to OVRTypes.LoadLibrary.
		/// </summary>
		private IntPtr DllOvrPtr
		{
			get;
			set;
		}

		/// <summary>
		/// Interface to Oculus runtime methods.
		/// </summary>
		protected OVRBase OVR
		{
			get;
			set;
		}
		#endregion

		#region Test setup
		/// <summary>
		/// Initialize the Oculus VR runtime.
		/// </summary>
		[TestInitialize]
		public virtual void Initialize()
		{
			if(Environment.Is64BitProcess)
				OVR = new OVR64();
			else
				OVR = new OVR32();

			OVRTypes.InitParams	initializationParameters	= new OVRTypes.InitParams();
			initializationParameters.Flags					= OVRTypes.InitFlags.Debug;
			initializationParameters.ConnectionTimeoutMS	= 0;
			initializationParameters.RequestedMinorVersion	= 0;
			initializationParameters.LogCallback			= LogCallback;

			OVRTypes.Result result = OVR.Initialize(initializationParameters);
			Assert.IsTrue(result >= OVRTypes.Result.Success);
		}

		/// <summary>
		/// Write a any log messages to the trace output.
		/// </summary>
		/// <param name="level">Error level of the message.</param>
		/// <param name="message">Message to display in the trace output.</param>
		protected void LogCallback(IntPtr userData, OVRTypes.LogLevel level, string message)
		{
			string formattedMessage = string.Format("[{0}] {1}", level.ToString(), message);
			System.Diagnostics.Trace.WriteLine(formattedMessage);
		}

		/// <summary>
		/// Shut down the Oculus VR runtime.
		/// </summary>
		[TestCleanup]
		public void Shutdown()
		{
			OVR.Shutdown();

			OVR.Dispose();
			OVR = null;
		}
		#endregion

		[TestMethod]
		public void Detect()
		{
			OVRTypes.DetectResult result = OVR.Detect(0);

			Assert.AreEqual(result.IsOculusServiceRunning, 1, "The Oculus service isn't running.");
			Assert.AreEqual(result.IsOculusHMDConnected, 1, "The HMD isn't connected.");
		}

		[TestMethod]
		public void GetLastErrorInfo()
		{
			ovrSession session	= CreateSession();
			
			OVRTypes.ErrorInfo errorInfo;

			OVR.GetLastErrorInfo(out errorInfo);
			Assert.IsTrue(errorInfo.Result == OVRTypes.Result.Success);
			Assert.IsTrue(string.IsNullOrEmpty(errorInfo.ErrorString));
		}

		[TestMethod]
		public void GetVersionString()
		{
			IntPtr versionPtr = OVR.GetVersionString();
			string version = Marshal.PtrToStringAnsi(versionPtr);
			Assert.IsNotNull(version);
			Assert.AreEqual("1.3.2", version);
		}

		[TestMethod]
		public void TraceMessage()
		{
			string message = "OculusWrapTest.TraceMessage unit test method ran successfully.";

			int length = OVR.TraceMessage(OVRTypes.LogLevel.Info, message);
			Assert.AreEqual(message.Length, length);
		}

		/// <remarks>
		/// Remember to turn on the Rift headset, before running this test.
		/// </remarks>
		[TestMethod]
		public void Session_Create()
		{
			IntPtr				session			= IntPtr.Zero;
			OVRTypes.GraphicsLuid	graphicsLuid	= new OVRTypes.GraphicsLuid();
			OVRTypes.Result			result;

			result = OVR.Create(ref session, ref graphicsLuid);
			Assert.IsTrue(result >= OVRTypes.Result.Success, "Failed to create a session. This usually indicates that the HMD is turned off.");
			Assert.AreNotEqual(IntPtr.Zero, session, "No session returned, even though create call succeeded.");
			
			OVRTypes.HmdDesc hmdDesc;
			if(Environment.Is64BitProcess)
			{
				// Retrieve the 64 bit HmdDesc.
				// In the Oculus SDK, the 64 bit HmdDesc contains padding characters that aren't present in the 32 bit HmdDesc.
				// In order to treat both versions of the HmdDesc the same, the 64 bit HmdDesc is copied to a new 32 bit HmdDesc, here.
				OVRTypes.HmdDesc64 hmdDesc64;
				OVR.GetHmdDesc64(out hmdDesc64, session);

				// Create a 32 bit HmdDesc, based on the 64 bit HmdDesc.
				hmdDesc = new OVRTypes.HmdDesc(hmdDesc64);
			}
			else
				OVR.GetHmdDesc32(out hmdDesc, session);

			string manufacturer = System.Text.Encoding.ASCII.GetString(hmdDesc.Manufacturer).TrimEnd((char) 0);
			Assert.AreEqual("Oculus VR", manufacturer);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[0].LeftTan > 1f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[0].LeftTan < 2f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[0].RightTan > 1f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[0].RightTan < 2f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[0].UpTan > 1f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[0].UpTan < 2f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[0].DownTan > 1f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[0].DownTan < 2f);

			Assert.IsTrue(hmdDesc.DefaultEyeFov[1].LeftTan > 1f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[1].LeftTan < 2f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[1].RightTan > 1f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[1].RightTan < 2f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[1].UpTan > 1f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[1].UpTan < 2f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[1].DownTan > 1f);
			Assert.IsTrue(hmdDesc.DefaultEyeFov[1].DownTan < 2f);
		}

		/// <remarks>
		/// Remember to turn on the Rift headset, before running this test.
		/// </remarks>
		[TestMethod]
		public void Session_Destroy()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session, "Failed to create session.");

			OVR.Destroy(session);
		}

		[TestMethod]
		public void Session_GetTrackerCount()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session, "Failed to create session.");

			uint count = OVR.GetTrackerCount(session);
			Assert.IsTrue(count >= 1, "No tracker found.");
			Assert.IsTrue(count < 99, "Too many trackers found.");
		}

		[TestMethod]
		public void Session_GetTrackerDesc()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session, "Failed to create session.");

			OVRTypes.TrackerDesc trackerDescription = OVR.GetTrackerDesc(session, 0);
			Assert.IsTrue(trackerDescription.FrustumNearZInMeters > 0f);
			Assert.IsTrue(trackerDescription.FrustumNearZInMeters < 100f);
			Assert.IsTrue(trackerDescription.FrustumFarZInMeters > 0f);
			Assert.IsTrue(trackerDescription.FrustumFarZInMeters < 100f);
			Assert.IsTrue(trackerDescription.FrustumHFovInRadians > Math.PI/4);
			Assert.IsTrue(trackerDescription.FrustumHFovInRadians < Math.PI);	
			Assert.IsTrue(trackerDescription.FrustumVFovInRadians > Math.PI/4);
			Assert.IsTrue(trackerDescription.FrustumVFovInRadians < Math.PI);
		}

		[TestMethod]
		public void Session_GetSessionStatus()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session, "Failed to create session.");

			OVRTypes.SessionStatus sessionStatus = new OVRTypes.SessionStatus();
			OVRTypes.Result result = OVR.GetSessionStatus(session, ref sessionStatus);
			Assert.IsTrue(result >= OVRTypes.Result.Success);
			Assert.AreEqual(sessionStatus.HmdPresent, 1);
		}

		[TestMethod]
		public void Session_GetSetTrackingOriginType()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session, "Failed to create session.");

			OVRTypes.Result result = OVR.SetTrackingOriginType(session, OVRTypes.TrackingOrigin.EyeLevel);
			Assert.IsTrue(result >= OVRTypes.Result.Success);

			OVRTypes.TrackingOrigin trackingOrigin = OVR.GetTrackingOriginType(session);
			Assert.AreEqual(OVRTypes.TrackingOrigin.EyeLevel, trackingOrigin);

			result = OVR.SetTrackingOriginType(session, OVRTypes.TrackingOrigin.FloorLevel);
			Assert.IsTrue(result >= OVRTypes.Result.Success);

			trackingOrigin = OVR.GetTrackingOriginType(session);
			Assert.AreEqual(OVRTypes.TrackingOrigin.FloorLevel, trackingOrigin);
		}

		[TestMethod]
		public void Session_RecenterTrackingOrigin()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session, "Failed to create session.");

			OVRTypes.Result result = OVR.RecenterTrackingOrigin(session);

			if(result == OVRTypes.Result.InvalidHeadsetOrientation)
				Assert.Fail("The headset couldn't be seen by the tracker.");

			Assert.IsTrue(result >= OVRTypes.Result.Success);
		}

		[TestMethod]
		public void Session_ClearShouldRecenterFlag()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session, "Failed to create session.");

			OVR.ClearShouldRecenterFlag(session);
		}

		[TestMethod]
		public void Session_GetTrackerPose()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session, "Failed to create session.");

			OVRTypes.TrackerPose trackerPose = OVR.GetTrackerPose(session, 0);

			Assert.IsTrue(trackerPose.LeveledPose.Position.X > -2f && trackerPose.LeveledPose.Position.X < 2f);
			Assert.IsTrue(trackerPose.LeveledPose.Position.Y > -2f && trackerPose.LeveledPose.Position.Y < 2f);
			Assert.IsTrue(trackerPose.LeveledPose.Position.Z > -2f && trackerPose.LeveledPose.Position.Z < 2f);

			Assert.IsTrue(trackerPose.LeveledPose.Orientation.X > -2f && trackerPose.LeveledPose.Orientation.X < 2f);
			Assert.IsTrue(trackerPose.LeveledPose.Orientation.Y > -2f && trackerPose.LeveledPose.Orientation.Y < 2f);
			Assert.IsTrue(trackerPose.LeveledPose.Orientation.Z > -2f && trackerPose.LeveledPose.Orientation.Z < 2f);
			Assert.IsTrue(trackerPose.LeveledPose.Orientation.W > -2f && trackerPose.LeveledPose.Orientation.W < 2f);

			Assert.IsTrue(trackerPose.Pose.Position.X > -2f && trackerPose.Pose.Position.X < 2f);
			Assert.IsTrue(trackerPose.Pose.Position.Y > -2f && trackerPose.Pose.Position.Y < 2f);
			Assert.IsTrue(trackerPose.Pose.Position.Z > -2f && trackerPose.Pose.Position.Z < 2f);

			Assert.IsTrue(trackerPose.Pose.Orientation.X > -2f && trackerPose.Pose.Orientation.X < 2f);
			Assert.IsTrue(trackerPose.Pose.Orientation.Y > -2f && trackerPose.Pose.Orientation.Y < 2f);
			Assert.IsTrue(trackerPose.Pose.Orientation.Z > -2f && trackerPose.Pose.Orientation.Z < 2f);
			Assert.IsTrue(trackerPose.Pose.Orientation.W > -2f && trackerPose.Pose.Orientation.W < 2f);

			Assert.AreNotEqual(OVRTypes.TrackerFlags.None, trackerPose.TrackerFlags, "The tracker is not connected.");
		}
		
		[TestMethod]
		public void Session_GetTrackingState()
		{
			ovrSession session = CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			OVRTypes.TrackingState trackingState;
			OVR.GetTrackingState(out trackingState, session, 0.0, 1);

			Assert.AreNotEqual(0, trackingState.HeadPose.ThePose.Orientation.X);
			Assert.AreNotEqual(0, trackingState.HeadPose.ThePose.Orientation.Y);
			Assert.AreNotEqual(0, trackingState.HeadPose.ThePose.Orientation.Z);
			Assert.AreNotEqual(1, trackingState.HeadPose.ThePose.Orientation.W);
		}

		[TestMethod]
		public void Session_GetInputState()
		{
			ovrSession session = CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			OVRTypes.InputState inputState = new OVRTypes.InputState();
			OVRTypes.Result result = OVR.GetInputState(session, OVRTypes.ControllerType.XBox, ref inputState);

			if(result == OVRTypes.Result.DeviceUnavailable)
				Assert.Fail("No XBox controller was available.");

			Assert.IsTrue(result >= OVRTypes.Result.Success, "Failed to retrieve the input state of the XBox controller.");
		}

		[TestMethod]
		public void Session_GetConnectedControllerTypes()
		{
			ovrSession session = CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			OVRTypes.ControllerType controllerType = OVR.GetConnectedControllerTypes(session);

			Assert.IsTrue(controllerType.HasFlag(OVRTypes.ControllerType.XBox), "No XBox controller was available.");
		}

		[TestMethod]
		public void Session_SetControllerVibration()
		{
			ovrSession session = CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			OVRTypes.Result result = OVR.SetControllerVibration(session, OVRTypes.ControllerType.Touch, 0.5f, 0.75f);
			
			// TODO: Enable again when touch controllers are attached.
			//Assert.IsTrue(result >= OVRost.Result.Success, "Failed to set controller vibration on the touch controller.");
		}

		[TestMethod]
		public void Session_GetFovTextureSize()
		{
			ovrSession session = CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			OVRTypes.FovPort fieldOfView	= new OVRTypes.FovPort();
			fieldOfView.DownTan				= (float) Math.Tan(0.523598776); // 0.523598776 radians = 30 degrees.
			fieldOfView.UpTan				= (float) Math.Tan(0.523598776); // 0.523598776 radians = 30 degrees.
			fieldOfView.LeftTan				= (float) Math.Tan(0.785398163); // 0.785398163 radians = 45 degrees.
			fieldOfView.RightTan			= (float) Math.Tan(0.785398163); // 0.785398163 radians = 45 degrees.

			OVRTypes.Sizei size = OVR.GetFovTextureSize(session, OVRTypes.EyeType.Left, fieldOfView, 1.0f);
			Assert.AreEqual(1099, size.Width);
			Assert.AreEqual(635, size.Height);
		}

		[TestMethod]
		public void Session_GetRenderDesc()
		{
			ovrSession session = CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			// Define field of view (This is used for both left and right eye).
			OVRTypes.FovPort fieldOfView	= new OVRTypes.FovPort();
			fieldOfView.DownTan				= (float) Math.Tan(0.523598776); // 0.523598776 radians = 30 degrees.
			fieldOfView.UpTan				= (float) Math.Tan(0.523598776); // 0.523598776 radians = 30 degrees.
			fieldOfView.LeftTan				= (float) Math.Tan(0.785398163); // 0.785398163 radians = 45 degrees.
			fieldOfView.RightTan			= (float) Math.Tan(0.785398163); // 0.785398163 radians = 45 degrees.

			OVRTypes.EyeRenderDesc renderDesc = OVR.GetRenderDesc(session, OVRTypes.EyeType.Left, fieldOfView);
			Assert.AreEqual(renderDesc.Fov, renderDesc.Fov);
		}

		[TestMethod]
		public void Session_GetPredictedDisplayTime()
		{
			ovrSession session = CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			double frameMidPoint = OVR.GetPredictedDisplayTime(session, 0);
			Assert.IsTrue(frameMidPoint >= 0);
		}

		[TestMethod]
		public void GetTimeInSeconds()
		{
			double time = OVR.GetTimeInSeconds();
			Assert.AreNotEqual(0, time);
		}

		[TestMethod]
		public void ovrMatrix4f_Projection()
		{
			// Define field of view (This is used for both left and right eye).
			OVRTypes.FovPort fieldOfView = new OVRTypes.FovPort();

			fieldOfView.DownTan		= (float) Math.Tan(0.523598776); // 0.523598776 radians = 30 degrees.
			fieldOfView.UpTan		= (float) Math.Tan(0.523598776); // 0.523598776 radians = 30 degrees.
			fieldOfView.LeftTan		= (float) Math.Tan(0.785398163); // 0.785398163 radians = 45 degrees.
			fieldOfView.RightTan	= (float) Math.Tan(0.785398163); // 0.785398163 radians = 45 degrees.
			
			// Create left handed projection matrix.
			OVRTypes.Matrix4f matrix = OVR.Matrix4f_Projection(fieldOfView, 0.1f, 1, 0);
			Assert.IsTrue(matrix.M11 != 0);
			Assert.IsTrue(matrix.M22 != 0);
			Assert.IsTrue(matrix.M33 != 0);
		}

		[TestMethod]
		public void TimewarpProjectionDesc_FromProjection()
		{
			// Define field of view (This is used for both left and right eye).
			OVRTypes.FovPort fieldOfView = new OVRTypes.FovPort();

			fieldOfView.DownTan		= (float) Math.Tan(0.523598776); // 0.523598776 radians = 30 degrees.
			fieldOfView.UpTan		= (float) Math.Tan(0.523598776); // 0.523598776 radians = 30 degrees.
			fieldOfView.LeftTan		= (float) Math.Tan(0.785398163); // 0.785398163 radians = 45 degrees.
			fieldOfView.RightTan	= (float) Math.Tan(0.785398163); // 0.785398163 radians = 45 degrees.
			
			// Create left handed projection matrix, used to create a timewarp projection description.
			OVRTypes.Matrix4f matrix = OVR.Matrix4f_Projection(fieldOfView, 0.1f, 1, 0);

			OVRTypes.TimewarpProjectionDesc timewarpProjectionDesc = OVR.TimewarpProjectionDesc_FromProjection(matrix, OVRTypes.ProjectionModifier.None);
			Assert.IsTrue(timewarpProjectionDesc.Projection22 != 0);
			Assert.IsTrue(timewarpProjectionDesc.Projection23 != 0);
			Assert.IsTrue(timewarpProjectionDesc.Projection32 != 0);
		}

		[TestMethod]
		public void ovrMatrix4f_OrthoSubProjection()
		{
			OVRTypes.Matrix4f projectionMatrix = new OVRTypes.Matrix4f();
			projectionMatrix.M11	= 1;
			projectionMatrix.M22	= 1;
			projectionMatrix.M33	= 1;
			projectionMatrix.M44	= 1;

			OVRTypes.Vector2f vector = new OVRTypes.Vector2f();
			vector.X = 1;
			vector.Y = 1;

			OVRTypes.Matrix4f matrix = OVR.Matrix4f_OrthoSubProjection(projectionMatrix, vector, 1f, 1f);
			Assert.AreEqual( 1, matrix.M11);
			Assert.AreEqual(-1, matrix.M22);
			Assert.AreEqual( 0, matrix.M33);
			Assert.AreEqual( 1, matrix.M44);
		}

		[TestMethod]
		public void CalcEyePoses()
		{
			ovrSession session = CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			OVRTypes.Vector3f[]	hmdToEyeViewOffset	= new OVRTypes.Vector3f[2];
			OVRTypes.Posef[]	eyePoses			= new OVRTypes.Posef[2];
			OVRTypes.Posef		headPose			= new OVRTypes.Posef();

			hmdToEyeViewOffset[0].X	= -0.1f;
			hmdToEyeViewOffset[1].X	= 0.1f;

			// Define a head position looking forward, from a position where the head is 1.75 meters above the ground.
			headPose.Orientation.W				= 1;
			headPose.Position.Y					= 1.75f;

			IntPtr	posesPtr	= IntPtr.Zero;

			try
			{
				int poseFSize	= Marshal.SizeOf(typeof(OVRTypes.Posef));
				posesPtr		= Marshal.AllocHGlobal(poseFSize*2);
				Marshal.StructureToPtr(eyePoses[0], posesPtr, false);
				Marshal.StructureToPtr(eyePoses[1], posesPtr+poseFSize, false);

				OVR.CalcEyePoses(headPose, hmdToEyeViewOffset, posesPtr);

				eyePoses[0] = (OVRTypes.Posef) Marshal.PtrToStructure(posesPtr, typeof(OVRTypes.Posef));
				eyePoses[1] = (OVRTypes.Posef) Marshal.PtrToStructure(posesPtr+poseFSize, typeof(OVRTypes.Posef));

				Assert.AreEqual(headPose.Orientation.X, eyePoses[0].Orientation.X);
				Assert.AreEqual(headPose.Orientation.Y, eyePoses[0].Orientation.Y);
				Assert.AreEqual(headPose.Orientation.Z, eyePoses[0].Orientation.Z);
				Assert.AreEqual(headPose.Orientation.W, eyePoses[0].Orientation.W);
				Assert.AreEqual(hmdToEyeViewOffset[0].X, eyePoses[0].Position.X);
				Assert.AreEqual(headPose.Position.Y, eyePoses[0].Position.Y);
				Assert.AreEqual(0, eyePoses[0].Position.Z);

				Assert.AreEqual(headPose.Orientation.X, eyePoses[1].Orientation.X);
				Assert.AreEqual(headPose.Orientation.Y, eyePoses[1].Orientation.Y);
				Assert.AreEqual(headPose.Orientation.Z, eyePoses[1].Orientation.Z);
				Assert.AreEqual(headPose.Orientation.W, eyePoses[1].Orientation.W);
				Assert.AreEqual(hmdToEyeViewOffset[1].X, eyePoses[1].Position.X);
				Assert.AreEqual(headPose.Position.Y, eyePoses[1].Position.Y);
				Assert.AreEqual(0, eyePoses[1].Position.Z);
			}
			finally
			{
				if(posesPtr != IntPtr.Zero)
					Marshal.FreeHGlobal(posesPtr);
			}

		}

		[TestMethod]
		public void Session_GetEyePoses()
		{
			ovrSession session = CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			OVRTypes.Vector3f[]		hmdToEyeViewOffset	= new OVRTypes.Vector3f[2];
			OVRTypes.Posef[]		poses				= new OVRTypes.Posef[2];
			IntPtr					sensorSampleTimePtr	= IntPtr.Zero;
			double?					sensorSampleTime	= null;
			IntPtr					posesPtr			= IntPtr.Zero;

			hmdToEyeViewOffset[0].X	= -0.1f;
			hmdToEyeViewOffset[1].X	= 0.1f;

			try
			{
				int poseFSize	= Marshal.SizeOf(typeof(OVRTypes.Posef));
				posesPtr		= Marshal.AllocHGlobal(poseFSize*2);
				Marshal.StructureToPtr(poses[0], posesPtr, false);
				Marshal.StructureToPtr(poses[1], posesPtr+poseFSize, false);

				// Allocate a double, to be passed as a pointer to the ovr_GetEyePoses, such that the double 
				// value can be filled out.
				int sensorSampleTimeSize	= Marshal.SizeOf(typeof(double));
				sensorSampleTimePtr			= Marshal.AllocHGlobal(sensorSampleTimeSize);

				OVR.GetEyePoses(session, 0, 1, hmdToEyeViewOffset, posesPtr, sensorSampleTimePtr);

				poses[0]			= (OVRTypes.Posef) Marshal.PtrToStructure(posesPtr, typeof(OVRTypes.Posef));
				poses[1]			= (OVRTypes.Posef) Marshal.PtrToStructure(posesPtr+poseFSize, typeof(OVRTypes.Posef));
				sensorSampleTime	= (double) Marshal.PtrToStructure(sensorSampleTimePtr, typeof(double));

				Assert.AreNotEqual(0, poses[0].Orientation.W);
				Assert.AreNotEqual(0, poses[0].Position.X);
				Assert.AreNotEqual(0, poses[0].Position.Y);
				Assert.AreNotEqual(0, poses[0].Position.Z);
				Assert.AreNotEqual(0, poses[1].Orientation.W);
				Assert.AreNotEqual(0, poses[1].Position.X);
				Assert.AreNotEqual(0, poses[1].Position.Y);
				Assert.AreNotEqual(0, poses[1].Position.Z);
				Assert.AreNotEqual(0, hmdToEyeViewOffset[0].X);
				Assert.AreEqual(0, hmdToEyeViewOffset[0].Y);
				Assert.AreEqual(0, hmdToEyeViewOffset[0].Z);
				Assert.AreNotEqual(0, hmdToEyeViewOffset[1].X);
				Assert.AreEqual(0, hmdToEyeViewOffset[1].Y);
				Assert.AreEqual(0, hmdToEyeViewOffset[1].Z);
			}
			finally
			{
				if(posesPtr != IntPtr.Zero)
					Marshal.FreeHGlobal(posesPtr);

				if(sensorSampleTimePtr != IntPtr.Zero)
					Marshal.FreeHGlobal(sensorSampleTimePtr);
			}
		}

		[TestMethod]
		public void Session_Posef_FlipHandedness()
		{
			OVRTypes.Posef pose			= new OVRTypes.Posef();
			OVRTypes.Posef resultPose	= new OVRTypes.Posef();

			pose.Position		= new OVRTypes.Vector3f(1, 1, 1);
			pose.Orientation	= new OVRTypes.Quaternionf(1, 1, 1, 1);

			OVR.Posef_FlipHandedness(ref pose, ref resultPose);

			Assert.AreEqual(pose.Position.X, -resultPose.Position.X);
			Assert.AreEqual(pose.Position.Y, resultPose.Position.Y);
			Assert.AreEqual(pose.Position.Z, resultPose.Position.Z);

			Assert.AreEqual(-pose.Orientation.X, resultPose.Orientation.X);
			Assert.AreEqual(pose.Orientation.Y, resultPose.Orientation.Y);
			Assert.AreEqual(pose.Orientation.Z, resultPose.Orientation.Z);
			Assert.AreEqual(-pose.Orientation.W, resultPose.Orientation.W);
		}

		[TestMethod]
		public void Session_GetBool()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			byte result = OVR.GetBool(session, "DummyValue", 1);
			Assert.AreEqual(1, result);
		}

		[TestMethod]
		public void Session_SetBool()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			byte success = OVR.SetBool(session, OVRTypes.OVR_DEBUG_HUD_STEREO_GUIDE_INFO_ENABLE, 1);
			Assert.AreEqual(1, success);
		}

		[TestMethod]
		public void Session_GetInt()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			int result = OVR.GetInt(session, "DummyValue", 2);
			Assert.AreEqual(2, result);
		}

		[TestMethod]
		public void Session_SetInt()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			byte success = OVR.SetInt(session, "DummyValue", 1);
			Assert.AreEqual(0, success);
		}

		[TestMethod]
		public void ovr_GetFloat()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			float result = OVR.GetFloat(session, "DummyValue", 2f);
			Assert.AreEqual(2f, result);
		}

		[TestMethod]
		public void Session_SetFloat()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			byte success = OVR.SetFloat(session, "DummyValue", 2f);
			Assert.AreEqual(0, success);
		}

		[TestMethod]
		public void Session_GetFloatArray()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			float[] values = new float[1];
			uint result = OVR.GetFloatArray(session, "DummyValue", values, (uint) values.Length);
			Assert.AreEqual(0u, result);
		}

		[TestMethod]
		public void Session_SetFloatArray()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			float[] values = new float[1];
			byte success = OVR.SetFloatArray(session, "DummyValue", values, (uint) values.Length);
			Assert.AreEqual(0, success);
		}
		
		[TestMethod]
		public void Session_GetString()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			IntPtr resultPtr = OVR.GetString(session, "DummyValue", string.Empty);
			string result = Marshal.PtrToStringAuto(resultPtr);
			Assert.IsNotNull(result);
		}

		[TestMethod]
		public void Session_SetString()
		{
			ovrSession session	= CreateSession();
			Assert.AreNotEqual(IntPtr.Zero, session);

			byte success = OVR.SetString(session, "DummyValue", "New value");
			Assert.AreEqual(0, success);
		}
	}
}
